package org.tomcat.demo.httpServer.applicationConnector.connector.http;

import java.io.IOException;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Stack;
import java.util.Vector;

import org.apache.catalina.Container;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.Logger;
import org.apache.catalina.connector.http.Constants;
import org.apache.catalina.util.StringManager;

public class HttpConnector implements Runnable {

	boolean stopped;
	private String threadName = null;
	private String scheme = "http";
	protected Container container = null;
	private Stack processors = new Stack();
	private Vector created = new Vector();
	protected int minProcessors = 5;
	private int maxProcessors = 20;
	private int curProcessors = 0;

	private StringManager sm = StringManager.getManager(Constants.Package);

	public String getScheme() {
		return scheme;
	}

	void recycle(HttpProcessor processor) {
		processors.push(processor);

	}
    public Container getContainer() {

        return (container);

    }
	@Override
	public void run() {
		ServerSocket serverSocket = null;
		int port = 8080;
		try {
			serverSocket = new ServerSocket(port, 1, InetAddress.getByName("127.0.0.1"));
		} catch (IOException e) {
			e.printStackTrace();
			System.exit(1);
		}
		while (!stopped) {
			// Accept the next incoming connection from the server socket
			Socket socket = null;
			try {
				socket = serverSocket.accept();
			} catch (Exception e) {
				continue;
			}
			// Hand this socket off to an HttpProcessor
			// HttpProcessor processor = new HttpProcessor(this);
			// Hand this socket off to an appropriate processor
			HttpProcessor processor = createProcessor();
			if (processor == null) {
				try {
					log(sm.getString("httpConnector.noProcessor"));
					socket.close();
				} catch (IOException e) {
				}
				continue;
			}
			processor.assign(socket);
		}
	}

	public void start() {
		Thread thread = new Thread(this);
		thread.start();
		while (curProcessors < minProcessors) {
			if ((maxProcessors > 0) && (curProcessors >= maxProcessors))
				break;
			HttpProcessor processor = newProcessor();
			recycle(processor);
		}
	}
	
    private HttpProcessor createProcessor() {

        synchronized (processors) {
            if (processors.size() > 0) {
                // if (debug >= 2)
                // log("createProcessor: Reusing existing processor");
                return ((HttpProcessor) processors.pop());
            }
            if ((maxProcessors > 0) && (curProcessors < maxProcessors)) {
                // if (debug >= 2)
                // log("createProcessor: Creating new processor");
                return (newProcessor());
            } else {
                if (maxProcessors < 0) {
                    // if (debug >= 2)
                    // log("createProcessor: Creating new processor");
                    return (newProcessor());
                } else {
                    // if (debug >= 2)
                    // log("createProcessor: Cannot create new processor");
                    return (null);
                }
            }
        }

    }
    
	private HttpProcessor newProcessor() {

		// if (debug >= 2)
		// log("newProcessor: Creating new processor");
		HttpProcessor processor = new HttpProcessor(this, curProcessors++);
		if (processor instanceof Lifecycle) {
			try {
				((Lifecycle) processor).start();
			} catch (LifecycleException e) {
				log("newProcessor", e);
				return (null);
			}
		}
		created.addElement(processor);
		return (processor);

	}

	private void log(String message, Throwable throwable) {

		Logger logger = container.getLogger();
		String localName = threadName;
		if (localName == null)
			localName = "HttpConnector";
		if (logger != null)
			logger.log(localName + " " + message, throwable);
		else {
			System.out.println(localName + " " + message);
			throwable.printStackTrace(System.out);
		}

	}

	private void log(String message) {
		Logger logger = container.getLogger();
		String localName = threadName;
		if (localName == null)
			localName = "HttpConnector";
		if (logger != null)
			logger.log(localName + " " + message);
		else
			System.out.println(localName + " " + message);

	}
}
